﻿using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace Daphne.Modularity.UI
{
    /// <summary>
    /// RegionManager class - for composing UI
    /// </summary>
    public class RegionManager: IRegionManager
    {
        /// <summary>
        /// Attribute containing reference to the dependency injection container
        /// </summary>
        private static IUnityContainer _unity;

        /// <summary>
        /// Map between views and viewmodels
        /// </summary>
        private Dictionary<Type, Type> _mapViewViewModel;

        /// <summary>
        /// Constructor
        /// </summary>
        public RegionManager()
        {
            _mapViewViewModel = new Dictionary<Type, Type>();
        }

        /// <summary>
        /// Registers the unity container
        /// </summary>
        public static void RegisterUnity(IUnityContainer unity)
        {
            _unity = unity;
        }

        /// <summary>
        /// Fills in the dependency properties for the instance
        /// </summary>
        /// <param name="instance"></param>
        public static void ResolveInstance(object instance)
        {
            // may be run by XAML designer
            if (_unity == null)
                return;

            // get property list
            // TO-DO: check, if we need to go to the base types
            // then solved by recursion
            var properties = instance.GetType().GetRuntimeProperties();

            // iterate properties
            foreach(var property in properties)
            {
                // if dependency attribute defined
                object[] attrList = property.GetCustomAttributes(typeof(DependencyAttribute), true).ToArray();
                if(attrList.Length > 0)
                {
                    // resolve the property
                    object bindValue = _unity.Resolve(property.PropertyType);
                    if(bindValue == null)
                        throw new InvalidOperationException("Object cannot be resolved: " + instance.ToString());

                    // set the value
                    property.SetValue(instance, bindValue);
                }
            }
        }

        /// <summary>
        /// Registers the view and viewmodel
        /// </summary>
        public void RegisterViewViewModel(Type view, Type viewModel)
        {
            _mapViewViewModel[view] = viewModel;
        }

        /// <summary>
        /// Registers the view and viewmodel
        /// </summary>
        public void RegisterViewViewModel<VIEW, VIEWMODEL>()
        {
            RegisterViewViewModel(typeof(VIEW), typeof(VIEWMODEL));
        }


        /// <summary>
        /// Resolves ViewModel for given view
        /// </summary>
        /// <typeparam name="VIEW"></typeparam>
        /// <returns></returns>
        public object ResolveViewModel(Type view)
        {
            // get view type
            Type typeVM;
            if (_mapViewViewModel.TryGetValue(view, out typeVM) == false)
                return null;

            // resolve viewmodel 
            object objViewModel = _unity.Resolve(typeVM);

            return objViewModel;            
        }
    }
}
